package com.magold.logic;

import org.andengine.audio.sound.Sound;
import org.andengine.entity.primitive.Line;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.shape.IAreaShape;
import org.andengine.extension.physics.box2d.PhysicsFactory;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.opengl.texture.region.ITiledTextureRegion;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.util.color.Color;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.joints.DistanceJointDef;
import com.magold.circuit.ICircuit;
import com.magold.circuit.ICircuitPath;
import com.magold.circuit.module.CircuitModule;
import com.magold.context.IContext;
import com.magold.physics.MagoldPhysicsConnector;
import com.magold.sprite.IMultiTextureSprite;
import com.magold.sprite.MultiTextureSprite;

public class PullSwitch implements ISpriteLogic, CircuitModule, GraspListener {
	public static abstract class Constants extends LogicConstants {
		protected ITiledTextureRegion mTexture;
		protected float mRopeWidth;
		protected Color mRopeColor;
		public Constants(IContext pActivity) {
			super(pActivity);
		}
	}
	
	private static FixtureDef sSwitchFixtureDef = PhysicsFactory.createFixtureDef(10.0f, 0.3f, 0.5f);
	private static Constants sConstants;
	public static void customized(Constants pConstants) {
		sConstants = pConstants;
	}
	
	private final PullTab mTab;
	private final float mDistance2Tab;
	private boolean mConnecting;
	private IMultiTextureSprite mSprite;
	private MagoldPhysicsConnector mConnector;
	
	public PullSwitch(float pDistance2Tab, boolean pInitConnecting) {
		mDistance2Tab = pDistance2Tab;
		mTab = new PullTab();
		mTab.setGrabListener(this);
		mConnecting = pInitConnecting;
	}
	
	@Override
	public MagoldPhysicsConnector findPhysicsConnector(IAreaShape pShape) {
		if (mSprite == pShape) return mConnector;
		return null;
	}

	@Override
	public boolean isConnected() {
		return mConnecting;
	}

	@Override
	public void createSceneData(float pX, float pY, float pRotation, float pScale, Scene pScene) {
		// create my sprite.
		VertexBufferObjectManager vbom = sConstants.mContext.getVertexBufferObjectManager();
		IMultiTextureSprite raw = new MultiTextureSprite(pX, pY, 0, sConstants.mTexture, vbom);
		mSprite = LogicSpriteWrapper.wrap(raw, pScale, sConstants, this, pRotation, pScene);
		
		float tabCenterX = mSprite.getWidth()/2;
		float tabCenterY = mSprite.getHeight()/2 + mDistance2Tab;
		float[] tabCenter = mSprite.convertLocalToSceneCoordinates(tabCenterX, tabCenterY);
		float tabX = tabCenter[0] - mTab.getWidth()/2;
		float tabY = tabCenter[1] - mTab.getHeight()/2;
		mTab.createSceneData(tabX, tabY, pRotation, pScale, pScene);
		
		float[] start = mSprite.getSceneCenterCoordinates();
		Line rope = new Rope(start, sConstants.mRopeWidth, vbom);
		pScene.attachChild(rope);
		
		setConnecting(mConnecting);
	}

	@Override
	public void createPhysicsData(PhysicsWorld pWorld) {
		// create my physics data.
		Body body = PhysicsFactory.createBoxBody(pWorld, mSprite, BodyType.StaticBody, sSwitchFixtureDef);
		mConnector = LogicPhysicsHelper.connectBody(pWorld, body, mSprite);
		mTab.createPhysicsData(pWorld);
		
		// create revolute joint.
		DistanceJointDef jointDef = new DistanceJointDef();
		Body tabBody = mTab.getBody();
		Vector2 center = tabBody.getWorldCenter();
		Vector2 pos = tabBody.getPosition();
		center.y = pos.y;
		jointDef.initialize(body, tabBody, body.getWorldCenter(), center);
		pWorld.createJoint(jointDef);
	}

	@Override
	public boolean isStatic() {
		return true;
	}

	@Override
	public void startCollide(ISpriteLogic pAnthor, Contact pContact) {
	}

	@Override
	public void endCollide(ISpriteLogic pAnthor, Contact pContact) {
	}

	@Override
	public void onGrasp() {
		setConnecting(!mConnecting);
		Sound s = sConstants.mContext.getSoundByName("switch.WAV");
		s.play();
	}
	
	private void setConnecting(boolean b) {
		mConnecting = b;
		if (mConnecting) {
			mSprite.setColor(Color.GREEN);
		} else {
			mSprite.setColor(Color.RED);
		}
	}

	@Override
	public void onRelease() {
	}
	
	private class Rope extends Line {
		public Rope(float[] pStart, float pWidth, VertexBufferObjectManager pVBOM) {
			super(pStart[0], pStart[1], 0, 0, sConstants.mRopeWidth, pVBOM);
			setColor(sConstants.mRopeColor);
		}
		
		@Override
		public void onManagedUpdate(float t) {
			super.onManagedUpdate(t);
			updatePosition();
		}
		
		private void updatePosition() {
			final float ratio = PIXEL_TO_METER_RATIO_DEFAULT;
			
			Body b = mTab.getBody();
			Vector2 localCenter = b.getLocalCenter();
			localCenter.y -= mTab.getHeight() / 2 / ratio;
			Vector2 end = b.getWorldPoint(localCenter);
			setPosition(getX1(), getY1(), end.x * ratio, end.y * ratio);
		}
	}

	@Override
	public void onCurrentBegin() {
	}

	@Override
	public void onCurrentEnd() {
	}

	@Override
	public void onPathJoined(ICircuit pCircuit, ICircuitPath pPath) {
	}

	private int mID;
	@Override
	public void setID(int pID) {
		mID = pID;
	}

	@Override
	public int getID() {
		return mID;
	}

	@Override
	public float[] getWireInPosition() {
		return mSprite.convertLocalToSceneCoordinates(20, 15);
	}

	@Override
	public float[] getWireOutPosition() {
		return mSprite.convertLocalToSceneCoordinates(10, 15);
	}

}
